package org.stream.answerduel.vo;


import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

import org.eclipse.paho.client.mqttv3.MqttException;
import org.stream.answerduel.service.*;
import org.stream.answerduel.vo.Message.*;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.stream.answerduel.vo.Message.EnumType.ResultType;

/**
 * 功能描述：游戏房间
 * @author 何俊霖
 */
@Data
@Slf4j
public class Room {

    private MQService mqService;
    private RobotService robotService;
    private UserService userService;
    private SubjectService subjectService;
    private Long roomID;
    private List<PlayingUser> playingUsers = new ArrayList<PlayingUser>(2);
    private List<SubjectMessage> subjects = new ArrayList<SubjectMessage>(10);
    private int currentIndex;
    private boolean isStart = false;
    private Timer timer = new Timer();//用于每秒判断一次看用户是否答题，如果10秒都没有答题，则自动答-1
    private Timer sendTimer = new Timer();//用于2秒号发送下一道题或者最终结果
    private Timer destroyTimer = new Timer();//用于5分钟后自动销毁房间，避免驻留内存
    private Timer readyTimer = new Timer();//用于5秒后自动准备

    public Room()
    {
        
    }

    /**
     * 功能描述：初始化一个好友对战的房间
     * @param roomID 房间ID
     * @param userA 用户A
     * @param userB 用户B
     * @param mqService 消息队列服务
     * @param userService 用户服务
     */
    public void init(Long roomID, WaitingUser userA, WaitingUser userB, MQService mqService, UserService userService,SubjectService subjectService) {
        robotService=RobotService.getInstance();
        this.roomID = roomID;
        this.playingUsers.add(new PlayingUser(userA));
        this.playingUsers.add(new PlayingUser(userB));
        this.mqService = mqService;
        this.userService = userService;
        this.subjectService = subjectService;
        autoReadyAfterTime(10000);
        destroyAfterTime(roomID, 3000000);
    }

    /**
     * 功能描述：初始化一个匹配对战的房间
     * @param roomID 房间ID
     * @param userA 用户A
     * @param userB 用户B
     * @param mqService 消息队列服务
     * @param userService 用户服务
     */
    public void init(Long roomID, MatchingUser userA, MatchingUser userB, MQService mqService, UserService userService,SubjectService subjectService) {
        robotService=RobotService.getInstance();
        this.roomID = roomID;
        this.playingUsers.add(new PlayingUser(userA));
        this.playingUsers.add(new PlayingUser(userB));

        // if(playingUsers.get(0).getPriority() == -1)//机器人自动准备
        //     playingUsers.get(0).setReady(true);
        // if(playingUsers.get(1).getPriority() == -1)
        //     playingUsers.get(1).setReady(true);
        this.mqService = mqService;
        this.userService = userService;
        this.subjectService = subjectService;
        autoReadyAfterTime(10000);
        destroyAfterTime(roomID, 3000000);
    }

    public void destroyAfterTime(Long roomID, long delay){
        destroyTimer.schedule(new TimerTask() 
        {
            public void run() {
                if(MatchThread.roomList.containsKey(roomID))
                    MatchThread.roomList.remove(roomID);
                
            }
        }, delay);
    }

    public void autoReadyAfterTime(long delay){
        readyTimer.schedule(new TimerTask()
        {
            public void run() {
                try {
                    setReady(0);
                    setReady(1);
                }catch (MqttException e){
                    e.printStackTrace();
                }
            }
        }, delay);
    }

    public boolean hasUser(long userID){
        boolean has = false;
        for(int i=0;i<playingUsers.size();i++){
            PlayingUser playingUser = playingUsers.get(i);
            if(playingUser.getId().equals(userID))
            {
                has = true;
                break;
            }
        }
        return has;
    }

//    public synchronized void exit(long userID)
//    {
//        for(int i=0;i<playingUsers.size();i++){
//            PlayingUser playingUser = playingUsers.get(i);
//            if(playingUser.getId().equals(userID) && isStart == false)
//            {
//                MatchThread.roomList.remove(roomID);
//                log.info("游戏房间："+roomID+"（游戏未开始）由于用户退出而自动销毁");
//                return;
//            }
//        }
//    }
    // @Override
    // public void doBiz()
    // {
    //     log.info("定时器");
    // }

    public void initSubjects(){
        List<SubjectVo> subjectVos = subjectService.getFiveSubject();
        for(int i=0;i<5;i++){
            SubjectVo subjectVo = subjectVos.get(i);
            String title = subjectVo.getSubjectDetails();
            int answer = subjectVo.getRightOption();
            List<String> options = subjectVo.getSubjectOptions();

            AnswerDetailsVo answerDetailsVo0 = new AnswerDetailsVo();
            AnswerDetailsVo answerDetailsVo1 = new AnswerDetailsVo();

            answerDetailsVo0.setRoomId(roomID);
            answerDetailsVo0.setAnswer(answer);
            answerDetailsVo0.setSubjectId(subjectVo.getSubjectID());

            answerDetailsVo1.setRoomId(roomID);
            answerDetailsVo1.setAnswer(answer);
            answerDetailsVo1.setSubjectId(subjectVo.getSubjectID());

            answerDetailsVo0.setUserId(playingUsers.get(0).getId());
            answerDetailsVo0.setRivalId(playingUsers.get(1).getId());
            playingUsers.get(0).getAnswers().add(answerDetailsVo0);

            answerDetailsVo1.setUserId(playingUsers.get(1).getId());
            answerDetailsVo1.setRivalId(playingUsers.get(0).getId());
            playingUsers.get(1).getAnswers().add(answerDetailsVo1);

            SubjectMessage subjectMessage = new SubjectMessage();
            subjectMessage.setCurrentIndex(i);
            subjectMessage.setTitle(title);
            subjectMessage.setOption(options);
            subjects.add(subjectMessage);
            //log.info(answer+"");
        }
    }

    public void testSubject()
    {
        Random random = new Random();
        for(int i=0;i<5;i++)
        {
            AnswerDetailsVo answerDetailsVo0 = new AnswerDetailsVo();
            AnswerDetailsVo answerDetailsVo1 = new AnswerDetailsVo();
            int answer = random.nextInt(4) + 1;
            //log.info(answer+" ");
            answerDetailsVo0.setAnswer(answer);
            answerDetailsVo1.setAnswer(answer);

            answerDetailsVo0.setUserId(playingUsers.get(0).getId());
            answerDetailsVo0.setRivalId(playingUsers.get(1).getId());
            playingUsers.get(0).getAnswers().add(answerDetailsVo0);

            answerDetailsVo1.setUserId(playingUsers.get(0).getId());
            answerDetailsVo1.setRivalId(playingUsers.get(1).getId());
            playingUsers.get(1).getAnswers().add(answerDetailsVo1);

            SubjectMessage subjectMessage = new SubjectMessage();
            int r1 = random.nextInt(100);
            int r2 = random.nextInt(100);
            subjectMessage.setCurrentIndex(i);
            subjectMessage.setTitle(r1+"+"+r2+"=?");
            List<String> options = new ArrayList<String>();
            for(int j=1;j<=4;j++)
            {
                if(j == answer)
                    options.add("" + (r1 + r2));
                else
                    options.add("" + (r1 + r2 + random.nextInt(100)));
            }
            subjectMessage.setOption(options);
            subjects.add(subjectMessage);
        }
    }

    /**
     * 功能描述：两秒后向双方发送下一道题目的信息
     * @author 何俊霖
     */
    private void sendNextSubject()
    {
        PlayingUser me = playingUsers.get(0);//我
        PlayingUser rival = playingUsers.get(1);//敌人

        List<AnswerDetailsVo> myAnswers = me.getAnswers();
        List<AnswerDetailsVo> rivalAnswers = rival.getAnswers();

        sendTimer = new Timer();
        sendTimer.schedule(new TimerTask()
        {
            public void run() {
                myAnswers.get(currentIndex + 1).setStartTimestamp(getCurrentTime());
                rivalAnswers.get(currentIndex + 1).setStartTimestamp(getCurrentTime());
                myAnswers.get(currentIndex + 1).setCanAnswer(true);
                rivalAnswers.get(currentIndex + 1).setCanAnswer(true);
                currentIndex++;

                SubjectMessage subjectMessage = subjects.get(currentIndex);
                if (me.getPriority() == -1) {
                    robotService.onDuty(me.getId(), roomID, myAnswers.get(currentIndex).getAnswer());
                }
                if (rival.getPriority() == -1) {
                    robotService.onDuty(rival.getId(), roomID, rivalAnswers.get(currentIndex).getAnswer());
                }
                try {
                    mqService.publish(subjectMessage.toString(), "/public/TEST/" + me.getWechatID());
                    mqService.publish(subjectMessage.toString(), "/public/TEST/" + rival.getWechatID());
                } catch (MqttException e) {
                    e.printStackTrace();
                }
                log.info(subjectMessage.toString());
            }
        }, 2000);

        
    }

    /**
     * 功能描述：处理最终比赛结果，写数据库，两秒后向双方发送最终比赛结果
     * @author 何俊霖
     */
    public void sendFinalResult(){
        PlayingUser me = playingUsers.get(0);// 我
        PlayingUser rival = playingUsers.get(1);// 敌人

        List<AnswerDetailsVo> myAnswers = me.getAnswers();
        List<AnswerDetailsVo> rivalAnswers = rival.getAnswers();

        ResultMessage myResultMessage = new ResultMessage();
        ResultMessage rivalResultMessage = new ResultMessage();
        String winner;
        if (me.getTotalScore() > rival.getTotalScore()) 
        {
            myResultMessage.setResultType(ResultType.win);
            rivalResultMessage.setResultType(ResultType.lose);
            winner = me.getNickName();
            me.setScore(me.getScore() + me.getTotalScore());
            me.setWinCount(me.getWinCount()+1);
            rival.setLoseCount(rival.getLoseCount()+1);
        } else if (me.getTotalScore() < rival.getTotalScore()) 
        {
            myResultMessage.setResultType(ResultType.lose);
            rivalResultMessage.setResultType(ResultType.win);
            winner = rival.getNickName();
            rival.setScore(rival.getScore() + rival.getTotalScore());
            rival.setWinCount(rival.getWinCount()+1);
            me.setLoseCount(me.getLoseCount()+1);
        } else 
        {
            myResultMessage.setResultType(ResultType.draw);
            rivalResultMessage.setResultType(ResultType.draw);
            winner = "平局";
            me.setScore(me.getScore() + me.getTotalScore() / 2);
            rival.setScore(rival.getScore() + rival.getTotalScore() / 2);
            me.setDrawCount(me.getDrawCount()+1);
            rival.setDrawCount(rival.getDrawCount()+1);
        }
        myResultMessage.setRightCount(getTotalRightCount(myAnswers));
        myResultMessage.setWrongCount(getTotalWrongCount(myAnswers));
        myResultMessage.setNoChoiceCount(getTotalNoChoiceCount(myAnswers));
        rivalResultMessage.setRightCount(getTotalRightCount(rivalAnswers));
        rivalResultMessage.setWrongCount(getTotalWrongCount(rivalAnswers));
        rivalResultMessage.setNoChoiceCount(getTotalNoChoiceCount(rivalAnswers));

        sendTimer.schedule(new TimerTask()
        {
            public void run() {
                try {
                    mqService.publish(myResultMessage.toString(), "/public/TEST/" + me.getWechatID());
                    mqService.publish(rivalResultMessage.toString(), "/public/TEST/" + rival.getWechatID());
                } catch (MqttException e) {
                    e.printStackTrace();
                }
                
                log.info("游戏结束，胜利者：" + winner + " 我的原来的分数：" + me.getScore() + " 我的该局总得分：" + me.getTotalScore());
                me.setRightCount(me.getRightCount() + myResultMessage.getRightCount());
                me.setWrongCount(me.getWrongCount() + myResultMessage.getWrongCount());
                rival.setRightCount(rival.getRightCount() + rivalResultMessage.getRightCount());
                rival.setWrongCount(rival.getWrongCount() + rivalResultMessage.getWrongCount());
                if (me.getPriority() != -1)
                    userService.update(me);
                if (rival.getPriority() != -1)
                    userService.update(rival);
                if (me.getPriority() == -1) {
                    robotService.findRobotById(me.getId()).setOnDuty(false);
                }
                if (rival.getPriority() == -1) {
                    robotService.findRobotById(rival.getId()).setOnDuty(false);
                }
                MatchThread.roomList.remove(roomID);
                timer.cancel();
            }
        }, 2000);

        
    }

    /**
     * 
     * @param i 第i个用户，只有0和1
     * @param choice 该用户的选择，范围1-4，对应ABCD
     * @return 该用户本次答题的结果
     * @throws MqttException
     */
    public AnswerResultVo setUserChoice(int i, int choice) throws MqttException
    {
        // if(choiceIndex != currentIndex)
        //     return null;
        if(currentIndex >= 10)
            return null;
        
        PlayingUser me = playingUsers.get(i);//我
        PlayingUser rival = playingUsers.get((i+1)%2);//敌人

        List<AnswerDetailsVo> myAnswers = me.getAnswers();
        List<AnswerDetailsVo> rivalAnswers = rival.getAnswers();

        if(myAnswers.get(currentIndex).isCanAnswer() == false || myAnswers.get(currentIndex).getStartTimestamp().longValue() == 0L)
        {
            log.error("用户名："+me.getNickName()+"的第"+currentIndex+"题的答题还没开始");
            return null;
        }

        if(myAnswers.get(currentIndex).getChoice() != 0)
        {    
            log.error("用户名："+me.getNickName()+"的第"+currentIndex+"题已经答过了");
            return null;//已经答题过就不能再答了
        }

        myAnswers.get(currentIndex).setEndTimeStamp(getCurrentTime());
        
        AnswerDetailsVo answerDetailsVo = myAnswers.get(currentIndex);
        answerDetailsVo.setChoice(choice);
        //answerDetailsVo.setTime(time);
        int time = (int)(myAnswers.get(currentIndex).getTime()/1000);
        if(time > 10)
            time = 10;
        if(time < 0)
            time = 0;

        answerDetailsVo.setTime(time);
        Integer answerScore = null;//我本次答题的分数
        if(answerDetailsVo.getChoice() == answerDetailsVo.getAnswer())
        {   
            answerScore = 10-time;
            answerDetailsVo.setScore(10-time);
        }
        else
            answerScore = 0;
        me.setTotalScore(me.getTotalScore() + answerScore) ;//将我的答题总分累加

        //使用MQTT将我的答题结果发送给对手
        AnswerMessage answerMessage = new AnswerMessage();
        answerMessage.setTime(time);
        answerMessage.setScore(answerScore);
        answerMessage.setTotalScore(me.getTotalScore());
        answerMessage.setChoice(choice);
        mqService.publish(answerMessage.toString(), "/public/TEST/"+rival.getWechatID());
        log.info("用户名："+me.getNickName()+"  第"+currentIndex+"题"+"   选择:"+choice+"   得分:"+answerScore+"   总得分："+me.getTotalScore()+"   作答时间:"+time);
        AnswerDetailsService.getInstance().add(answerDetailsVo);
        //返回我的答题结果
        AnswerResultVo answerResultVo = new AnswerResultVo();
        answerResultVo.setScore(answerScore);
        answerResultVo.setTotalScore(me.getTotalScore());
        answerResultVo.setRightAnswer(myAnswers.get(currentIndex).getAnswer());

        if(rivalAnswers.get(currentIndex).getChoice() != 0)
         {  
            if(currentIndex == 4)
            {
                sendFinalResult();
                return answerResultVo;
            }
            
            //如果对手用户作答了，则发送下一道题目的信息
            sendNextSubject();
            
         }
        return answerResultVo;
    }

    /*
    public AnswerResultVo setUserBChoice(int choice,int time)throws MqttException
    {
        // if(choiceIndex != currentIndex)
        //     return null;
        if(currentIndex >=10)
            return null;
        
        AnswerDetailsVo answerDetailsVo = userB_answers.get(currentIndex);
        answerDetailsVo.setChoice(choice);
        answerDetailsVo.setTime(time);

        Integer answerScore = null;//该用户本次答题分数
        if(answerDetailsVo.getChoice() == answerDetailsVo.getAnswer())
        {
            answerScore = 10-time;
            answerDetailsVo.setScore(10-time);
        }
        else
            answerScore = 0;
        scoresB += answerScore;//该用户答题总分累加
        AnswerMessage answerMessage = new AnswerMessage();
        answerMessage.setTime(time);
        answerMessage.setScore(scoresB);
        mqService.publish(answerMessage.toString(), "/public/TEST/"+userA.getWechatID());//发送给另一个用户的回答结果信息
        log.info("用户ID："+userB.getId()+"  第"+currentIndex+"题"+"   选择："+choice+"   得分:"+answerScore+"   总得分："+scoresB+"   作答时间:"+time);
        AnswerResultVo answerResultVo = new AnswerResultVo();
        answerDetailsVo.setScore(answerScore);
        answerResultVo.setTotalScore(scoresB);

        if(userA_answers.get(currentIndex).getChoice() != 0)
         {
             //如果另一个用户作答了，则发送下一道题目的信息
            currentIndex++;
            SubjectMessage subjectMessage = subjects.get(currentIndex);

             if(userA.getPriority()==-1){
                 robotService.onDuty(userA.getId(),roomID,getUserA_answers().get(currentIndex).getAnswer());
             }
             if(userB.getPriority()==-1){
                 robotService.onDuty(userB.getId(),roomID,getUserB_answers().get(currentIndex).getAnswer());
             }
            mqService.publish(subjectMessage.toString(), "/public/TEST/"+userA.getWechatID());
            mqService.publish(subjectMessage.toString(), "/public/TEST/"+userB.getWechatID());
            log.info(subjectMessage.toString());

            timer.schedule(new TimerTask() {
                public void run() {
                    if(userA_answers.get(currentIndex).getChoice() <= 0)
                    {
                        try {
                            setUserAChoice(-1, 10);
                        } catch (MqttException e) {
                            e.printStackTrace();
                        }
                        log.info("房间号："+roomID+" 用户"+userA.getId()+"第"+currentIndex+"题"+"超时未答题");
                    }
                }
            }, 10000);
            timer.schedule(new TimerTask() {
                public void run() {
                    if(userB_answers.get(currentIndex).getChoice() <= 0)
                    {
                        try {
                            setUserBChoice(-1, 10);
                        } catch (MqttException e) {
                            e.printStackTrace();
                        }
                        log.info("房间号："+roomID+" 用户"+userB.getId()+"第"+currentIndex+"题"+"超时未答题");
                    }
                }
            }, 10000);
         }
        return answerResultVo;
    }
    */

    public void setReady(int i) throws MqttException
    {
        PlayingUser me = playingUsers.get(i);
        PlayingUser rival = playingUsers.get((i+1)%2);

        List<AnswerDetailsVo> myAnswers = me.getAnswers();
        List<AnswerDetailsVo> rivalAnswers = rival.getAnswers();
        if(me.isReady()){
            log.info("用户ID:"+me.getId()+"已经准备过了");
            return;
        }

        log.info("用户ID:"+me.getId()+"游戏准备完毕");
        me.setReady(true);
        if(rival.getPriority()==-1){
            setReady((i+1)%2);
            return;
        }
        if(rival.isReady())//如果对手也准备好了，就发送第一题
        {    
            isStart = true;
            //testSubject();
            initSubjects();
            SubjectMessage subjectMessage = subjects.get(0);
             if(me.getPriority()==-1){
                 robotService.onDuty(me.getId(),roomID,myAnswers.get(currentIndex).getAnswer());
             }
             if(rival.getPriority()==-1){
                 robotService.onDuty(rival.getId(),roomID,rivalAnswers.get(currentIndex).getAnswer());
             }
            mqService.publish(subjectMessage.toString(), "/public/TEST/"+me.getWechatID());
            mqService.publish(subjectMessage.toString(), "/public/TEST/"+rival.getWechatID());
            log.info(subjectMessage.toString());
            myAnswers.get(0).setStartTimestamp(getCurrentTime());
            rivalAnswers.get(0).setStartTimestamp(getCurrentTime());
            myAnswers.get(0).setCanAnswer(true);
            rivalAnswers.get(0).setCanAnswer(true);

            timer.schedule(new TimerTask() 
            {
                public void run() 
                {
                    PlayingUser me = playingUsers.get(0);//我
                    PlayingUser rival = playingUsers.get(1);//敌人

                    List<AnswerDetailsVo> myAnsewers = me.getAnswers();
                    List<AnswerDetailsVo> rivalAnsewers = rival.getAnswers();

                    if(getCurrentTime() - myAnsewers.get(currentIndex).getStartTimestamp() >= 10000)
                    {
                        if(myAnsewers.get(currentIndex).getChoice() == 0 && myAnsewers.get(currentIndex).getStartTimestamp().longValue() != 0L)
                            try {
                                setUserChoice(0, -1);
                            } catch (MqttException e) {
                                e.printStackTrace();
                            }
                    }
                    if(getCurrentTime() - rivalAnsewers.get(currentIndex).getStartTimestamp() >= 10000)
                    {
                        if(rivalAnsewers.get(currentIndex).getChoice() == 0 && rivalAnsewers.get(currentIndex).getStartTimestamp().longValue() != 0L)
                            try {
                                setUserChoice(1, -1);
                            } catch (MqttException e) {
                                e.printStackTrace();
                            }
                    }
                }
            }, 0, 1000);
        }
    }

    private int getTotalRightCount(List<AnswerDetailsVo> answers)
    {
        int count = 0;
        for(int i=0;i<answers.size();i++)
        {
            AnswerDetailsVo answer = answers.get(i);
            if(answer.getAnswer() == answer.getChoice())
                count++;
        }
        return count;
    }

    private int getTotalWrongCount(List<AnswerDetailsVo> answers)
    {
        int count = 0;
        for(int i=0;i<answers.size();i++)
        {
            AnswerDetailsVo answer = answers.get(i);
            if(answer.getChoice() != -1 && answer.getAnswer() != answer.getChoice())
                count++;
        }
        return count;
    }

    private int getTotalNoChoiceCount(List<AnswerDetailsVo> answers)
    {
        int count = 0;
        for(int i=0;i<answers.size();i++)
        {
            AnswerDetailsVo answer = answers.get(i);
            if(answer.getChoice() == -1)
                count++;
        }
        return count;
    }

    private long getCurrentTime()
    {
        return System.currentTimeMillis();
    }
    /*
    public void setReadyB() throws MqttException
    {
        log.info("用户ID:"+userB.getId()+"游戏准备完毕");
        readyB = true;
        if(userA.getPriority()==-1){
            setReadyA();
            return;
        }
        if(readyA)
        {    
            SubjectMessage subjectMessage = subjects.get(0);
             if(userA.getPriority()==-1){
                 robotService.onDuty(userA.getId(),roomID,getUserA_answers().get(currentIndex).getAnswer());
             }
             if(userB.getPriority()==-1){
                 robotService.onDuty(userB.getId(),roomID,getUserB_answers().get(currentIndex).getAnswer());
             }
            mqService.publish(subjectMessage.toString(), "/public/TEST/"+userA.getWechatID());
            mqService.publish(subjectMessage.toString(), "/public/TEST/"+userB.getWechatID());
            log.info(subjectMessage.toString());
            timer.schedule(new TimerTask() {
                public void run() {
                    if(userA_answers.get(currentIndex).getChoice() <= 0)
                    {
                        try {
                            setUserAChoice(-1, 10);
                        } catch (MqttException e) {
                            e.printStackTrace();
                        }
                        log.info("房间号："+roomID+" 用户"+userA.getId()+"第"+currentIndex+"题"+"超时未答题");
                    }
                }
            }, 10000);
            timer.schedule(new TimerTask() {
                public void run() {
                    if(userB_answers.get(currentIndex).getChoice() <= 0)
                    {
                        try {
                            setUserBChoice(-1, 10);
                        } catch (MqttException e) {
                            e.printStackTrace();
                        }
                        log.info("房间号："+roomID+" 用户"+userB.getId()+"第"+currentIndex+"题"+"超时未答题");
                    }
                }
            }, 10000);
        }
    }
    */
}